home *** CD-ROM | disk | FTP | other *** search
- /*
- * TEXTWINC.C - Text-windowing system (Curses Version)
- * (c)opyright Andrew Scott 1993
- *
- * Turbo C 2.0
- *
- * Description: Provides a simple text-menuing interface. Includes pop-down
- * menus, and scrolling windows. To use, set up a main window
- * with the MainWindow() function.
- * eg. MainWindow("Title", 2, "Files", 'f', "Help", 'h');
- *
- * Then set the commands and command-numbers for each menu use
- * the SetMenu function.
- * eg. SetMenu(0, 3, "Open",'o',0, "Close",'c',1, "Quit",'q',2);
- * SetMenu(1, 3, "Help",'h',3, "------------",-1,-1, "About",'a',4);
- *
- * Now just make a call to Choice() and the number it returns
- * will be the command-number of the choice
- * eg. If Help|About is chosen, 4 will be returned.
- *
- * If you want to get the user to select an option from a list
- * of options, make an array of strings with the option
- * descriptions in them (ensure final element is NULL). The
- * element number chosen will be returned (first element = 0)
- * after a call to ScrollChoice()
- * eg. If the array is a, and the maximum string length is l, make the call
- * ScrollChoice("BetterTitle", a, l);
- *
- * To display test inside a box, call DrawBox() with a NULL-
- * terminated array of strings.
- * eg. If the array is a, call
- * DrawBox(a);
- *
- * To display text inside a box, and then wait for a key to be
- * pressed, set up a NULL-terminated array of strings and call
- * the InfoBox() function
- * eg. If the array is a, make the call
- * InfoBox(a);
- *
- * If you want to get input as well as print a box, make a call
- * to DialogBox(), if nothing is entered, a default string is
- * returned
- * eg. DialogBox(a, "C:\") would return "C:\" if nothing was entered.
- *
- *
- * Author: Andrew Scott (Adrenalin Software)
- *
- * Date: 14/3/1993 ver 0.1
- * 17/4/1993 - converted to Curses (0.1a)
- */
-
- #include <curses.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
-
- /* Maximum number of chars in a menu title */
- #define MAXMENUWIDTH 9
- /* Maximum number of chars in a menu command */
- #define MAXCOMMWIDTH 12
-
- /* remove any old key definitions */
- #ifdef KEY_UP
- #undef KEY_UP
- #undef KEY_DOWN
- #undef KEY_LEFT
- #undef KEY_RIGHT
- #endif
-
- /* wgetch returns these values for these keys when they're pressed */
- #define CR '\r' /* sometimes '\n' */
- #define BS '\b'
- #define DEL 127
- #define ESC 27
- #define KEY_DOWN 0402
- #define KEY_UP 0403
- #define KEY_LEFT 0404
- #define KEY_RIGHT 0405
-
- typedef char *string;
-
- struct MenuStruct {
- char n[MAXCOMMWIDTH+1]; /* Item name ("" = no items) */
- int k; /* Key-press selector (lower case) */
- int x; /* Function reference number (-ve = no command) */
- };
- typedef struct MenuStruct *MenuItem;
-
- struct MenuBar {
- char n[MAXMENUWIDTH+1]; /* Menu name ("" = no menus) */
- int k; /* Key-press selector (lower case) */
- MenuItem m; /* Menu items */
- } *MainW;
-
- void MainWindow(string title, int num, ...)
- /* Post: Screen is set up with a nice title and num menus */
- {
- va_list args;
- string t;
- int i;
- struct MenuBar *c;
-
- c = MainW = (struct MenuBar *) malloc(sizeof(struct MenuBar) * (num + 1));
- va_start(args, num);
- initscr();
- raw(); /* startup mode.. use either this or cbreak() */
- noecho();
- keypad(stdscr, TRUE);
- scrollok(stdscr, FALSE);
- werase(stdscr);
- wmove(stdscr, 0, (COLS - strlen(title))/2);
- wprintw(stdscr, "%s", title);
- wmove(stdscr, 1, 1);
- for (i = num; i--; c++) {
- t = (va_arg(args, string));
- strcpy(c->n, t);
- wprintw(stdscr, "%-*s", MAXMENUWIDTH, t);
- c->k = (va_arg(args, int));
- c->m = NULL;
- }
- c->n[0] = 0;
- va_end(args);
- refresh();
- }
-
- void EndWindows()
- /* Post: Windows are freed up */
- {
- struct MenuBar *c;
- MenuItem t;
-
- for (c = MainW; c->n[0]; c++)
- free(c->m);
- free(MainW);
- delwin(curscr);
- endwin();
- }
-
- void SetMenu(int menu, int n, ...)
- /* Post: n commands has been set in menu #menu (0 = 1st) */
- {
- va_list args;
- string t;
- struct MenuBar *c1;
- MenuItem c2;
-
- int i;
-
- for (i = menu, c1 = MainW; i-- && c1->n[0]; c1++);
- if (! c1->n[0])
- return; /* error */
- c1->m = c2 = (MenuItem) malloc(sizeof(struct MenuStruct) * (n + 1));
- va_start(args, n);
- for (; n--; c2++) {
- t = va_arg(args, string);
- strcpy(c2->n, t);
- c2->k = va_arg(args, int);
- c2->x = va_arg(args, int);
- }
- c2->n[0] = 0;
- }
-
- WINDOW *MenuWin = NULL; /* ignore this unstructured global variable ;) */
-
- void PrintMenu(MenuItem m, int x)
- /* Post: The menu which is pointed to by m is printed at column x */
- {
- int i;
- MenuItem t;
-
- if (MenuWin != NULL) {
- werase(MenuWin);
- wrefresh(MenuWin);
- delwin(MenuWin);
- }
- for (i=0, t=m; t->n[0]; i++, t++);
- MenuWin = newwin(i+2, MAXCOMMWIDTH+4, 2, x-1);
- box(MenuWin, 0, 0);
- for (i=1; m->n[0]; i++) {
- wmove(MenuWin, i, 2);
- waddstr(MenuWin, (m++)->n);
- }
- wrefresh(MenuWin);
- }
-
- void ClearMenu()
- /* Post: The last menu printed is now gone */
- {
- werase(MenuWin);
- wrefresh(MenuWin);
- }
-
- void PrintComm(MenuItem m, int y)
- /* Post: Item *m is highlighted in current menu, position y */
- {
- wmove(MenuWin, y+1, 1);
- wprintw(MenuWin, "[%-*s]", MAXCOMMWIDTH, m->n);
- }
-
- void ClearComm(MenuItem m, int y)
- /* Post: Item *m is normalized in current menu, position y */
- {
- wmove(MenuWin, y+1, 1);
- wprintw(MenuWin, " %-*s ", MAXCOMMWIDTH, m->n);
- }
-
- void PrintBar(WINDOW *SWin, string s, int w, int y)
- /* Post: String s (width w) is highlighted in the window SWin on line y */
- {
- wmove(SWin, y, 0);
- wprintw(SWin, "[%-*s]", w, s);
- }
-
- void ClearBar(WINDOW *SWin, string s, int w, int y)
- /* Post: String s (width w) is normalized in the window SWin on line y */
- {
- wmove(SWin, y, 0);
- wprintw(SWin, " %-*s ", w, s);
- }
-
- void Beep()
- /* Post: Speaker has made a beep */
- {
- beep(); /* delete this line if your curses throw up on it */
- }
-
- int Choice()
- /*
- * Returns: a function reference number corresponding to a chosen command,
- * but returns -1 on an error.
- */
- {
- int ch;
- struct MenuBar *c;
- MenuItem p, q;
- int i, fx = -1, y;
-
- do {
- wmove(stdscr, LINES-1, 0);
- wprintw(stdscr, "Press the letter of the menu you wish to select.");
- refresh();
- ch = tolower(wgetch(stdscr));
- for (c = MainW, i = 0; c->n[0] && c->k != ch; c++, i++);
- i = MAXMENUWIDTH * i;
- if (c->n[0] != 0)
- do {
- wmove(stdscr, LINES-1, 0);
- wprintw(stdscr, "Press a letter, or use cursor keys and <RETURN> to select a command.");
- wmove(stdscr, 1, i);
- wprintw(stdscr, "[%s]", c->n);
- refresh();
- PrintMenu(p = c->m, i+1);
- PrintComm(p, y = 0);
- do {
- wrefresh(MenuWin);
- ch = tolower(wgetch(MenuWin));
- if (ch==KEY_UP) /** up-arrow */
- if (!y)
- Beep();
- else {
- ClearComm(p--, y--);
- PrintComm(p, y);
- }
- else if (ch==KEY_DOWN) /** down-arrow */
- if (! (p+1)->n[0])
- Beep();
- else {
- ClearComm(p++, y++);
- PrintComm(p, y);
- }
- else {
- for (q = c->m; q->n[0] && q->k != ch; q++);
- if (q->n[0])
- fx = q->x;
- }
- } while ((ch==KEY_UP || ch==KEY_DOWN) && fx < 0);
- if (ch==CR && fx < 0) /** return */
- fx = p->x;
- ClearMenu();
- wmove(stdscr, 1, i);
- wprintw(stdscr, " %s ", c->n);
- wmove(stdscr, LINES-1, 0);
- wclrtoeol(stdscr);
- if (ch==KEY_LEFT) /** left-arrow */
- if (!i)
- Beep();
- else {
- i -= MAXMENUWIDTH;
- c--;
- }
- else if (ch==KEY_RIGHT) /** right-arrow */
- if (! (c+1)->n[0])
- Beep();
- else {
- i += MAXMENUWIDTH;
- c++;
- }
- } while (ch != ESC && fx < 0);
- } while (fx < 0);
- refresh();
- return fx;
- }
-
- void ClearWin()
- /* Post: Area below command and title bars is clear */
- {
- wmove(stdscr, 2, 0);
- wclrtobot(stdscr);
- refresh();
- }
-
- int ScrollChoice(string title, string *sp, int w)
- /*
- * Returns: The offset of the string from s which is chosen, -1 on none
- * s points to the start of a list of strings, max length w, NULL term.
- */
- {
- string *srt, *end;
- int l, p, cur, ch, x = -1;
- WINDOW *ScrWin, *BorderWin;
-
- if (*sp==NULL) /* have to have at least 1 thing to print */
- return -1;
- if (strlen(title) > w)
- w = strlen(title);
- wmove(stdscr, LINES-1, 0);
- wprintw(stdscr, "Use cursor keys and <RETURN> to make a selection.");
- refresh();
- for (end = sp, l = 0; *end!=NULL && l < LINES-5; end++, l++);
- BorderWin = newwin(l+2, w+4, 2, 4);
- box(BorderWin, 0, 0);
- wrefresh(BorderWin);
- ScrWin = newwin(l, w+2, 3, 5);
- scrollok(ScrWin, FALSE);
- keypad(ScrWin, TRUE);
- p = l;
- srt = end;
- while (p--) {
- wmove(ScrWin, p, 1);
- waddstr(ScrWin, *(--srt));
- }
- PrintBar(ScrWin, *srt, w, p = 0);
- cur = 0;
- do {
- wrefresh(ScrWin);
- ch = tolower(wgetch(ScrWin));
- if (ch==KEY_UP)
- if (!cur)
- Beep();
- else if (p) {
- ClearBar(ScrWin, *(srt+p), w, p);
- p--;
- PrintBar(ScrWin, *(srt+p), w, p);
- cur--;
- } else {
- ClearBar(ScrWin, *(srt--), w, 0);
- wmove(ScrWin, 0, 0);
- winsertln(ScrWin);
- PrintBar(ScrWin, *srt, w, 0);
- end--;
- cur--;
- }
- else if (ch==KEY_DOWN)
- if (p==l-1 && *end==NULL)
- Beep();
- else if (p < l-1) {
- ClearBar(ScrWin, *(srt+p), w, p);
- p++;
- cur++;
- PrintBar(ScrWin, *(srt+p), w, p);
- } else {
- ClearBar(ScrWin, *(end-1), w, p);
- wmove(ScrWin, 0, 0);
- wdeleteln(ScrWin);
- cur++;
- PrintBar(ScrWin, *end, w, p);
- end++;
- srt++;
- }
- else if (ch==CR)
- x = cur;
- } while (x < 0 && ch != ESC);
- delwin(ScrWin);
- werase(BorderWin);
- wrefresh(BorderWin);
- delwin(BorderWin);
- ClearWin();
- return x;
- }
-
- WINDOW *PrintBox(string *sp, int *x, int *y, int *w)
- /*
- * Returns: The window in which the NULL-terminated array of strings pointed
- * to by sp is printed, y is set to be the offset to the bottom of the
- * window, and w is the width of it.
- */
- {
- int w1, i, j, k;
- string *c;
- WINDOW *BoxWin;
-
- if (*sp==NULL)
- return NULL;
- c = sp;
- for (w1 = strlen(*(c++)), i = 1; *c!=NULL; c++, i++)
- if (w1 < (j = strlen(*c)))
- w1 = j;
- j = 1 + (LINES - 5 - i)/2;
- *y = j + i;
- *w = k = w1 += 2;
- w1 = (COLS - 2 - w1)/2;
- *x = w1 + 1;
- BoxWin = newwin(i+2, k+2, j, w1);
- box(BoxWin, 0, 0);
- for (i = 1, c = sp; *c!=NULL; c++) {
- wmove(BoxWin, i++, 2);
- waddstr(BoxWin, *c);
- }
- wrefresh(BoxWin);
- return BoxWin;
- }
-
- void DrawBox(string *sp)
- /* Post: The NULL-terminated array of strings pointed to by sp is printed */
- {
- int k;
-
- delwin(PrintBox(sp, &k, &k, &k));
- }
-
- char InfoBox(string *sp)
- /*
- * Returns: The key pressed after the NULL-terminated array of strings
- * pointed to by sp is printed.
- */
- {
- int k;
- WINDOW *BoxWin;
-
- wmove(stdscr, LINES-1, 0);
- waddstr(stdscr, "Please press a key.");
- refresh();
- BoxWin = PrintBox(sp, &k, &k, &k);
- k = wgetch(stdscr);
- werase(BoxWin);
- wrefresh(BoxWin);
- delwin(BoxWin);
- ClearWin();
- return k;
- }
-
- string DialogBox(string *sp, string def)
- /* Pre: def != NULL */
- /*
- * Returns: The string entered (or def if none entered), after printing
- * box filled with NULL-terminated strings sp.
- */
- {
- int x, y, w, ch, i=0;
- string s;
- WINDOW *DiagWin, *TextWin;
-
- wmove(stdscr, LINES-1, 0);
- waddstr(stdscr, "Enter text, and when you are finished, press <RETURN>.");
- refresh();
- DiagWin = PrintBox(sp, &x, &y, &w);
- s = (string) malloc(w+1);
- strcpy(s, def);
- TextWin = newwin(1, w, y, x);
- scrollok(TextWin, FALSE);
- keypad(TextWin, TRUE);
- wmove(TextWin, 0, 0);
- waddstr(TextWin, s);
- wmove(TextWin, 0, 0);
- x = strlen(s);
- do {
- wrefresh(TextWin);
- ch = wgetch(TextWin);
- if (ch==BS || ch==DEL)
- if (!i)
- Beep();
- else {
- wprintw(TextWin, "\b");
- wclrtoeol(TextWin);
- x = --i;
- }
- else if (ch==KEY_LEFT)
- if (!i)
- Beep();
- else {
- wprintw(TextWin, "\b");
- i--;
- }
- else if (ch==KEY_RIGHT)
- if (i==x)
- Beep();
- else {
- waddch(TextWin, s[i]);
- i++;
- }
- else if (ch>31 && ch<127)
- if (i==w-1)
- Beep();
- else {
- waddch(TextWin, ch);
- if (i==x)
- x++;
- s[i++] = ch;
- }
- } while (ch!=CR && ch!=ESC);
- s[i] = 0;
- if (ch==ESC) {
- free(s);
- strcpy(s = (string) malloc(strlen(def)+1), def);
- }
- delwin(TextWin);
- werase(DiagWin);
- wrefresh(DiagWin);
- delwin(DiagWin);
- ClearWin();
- return s;
- }
-
- /*
- * This main function is for testing the basics of these routines.
- * Leave it commented out when creating object files.
- *
- main()
- {
- string scrolly[] = {
- "First one",
- "Second option",
- "3rd",
- "4th",
- "Fifth",
- "This could go on for AGES",
- "Why not stop soon?",
- "Ok",
- "How about the next one",
- "Done",
- "Nope",
- "Here's another few..",
- "Un",
- "Deux",
- "Trois",
- "Quatre",
- "When should I stop?",
- "Not yet obviously.",
- "Cinq",
- "Six",
- "Sept",
- "I think that's enough",
- "Well maybe one more.",
- NULL
- };
- string diagbox[] = {
- "Please enter some gibberish",
- "below at the prompt please.",
- "It WONT check your spelling.",
- "",
- "",
- NULL
- };
- string s;
-
- MainWindow("Big Huge Title", 3, "Ace", 'a', "Bee", 'b', "seaCide", 'c');
- SetMenu(0, 3, "First", 'f', 1, "------------", -1, -1, "Second", 's', 2);
- SetMenu(1, 1, "Spelling", 's', 3);
- SetMenu(2, 2, "I'd like", 'i', 4, "To be beside", 't', 5);
- while (1)
- switch (Choice()) {
- case 1:
- ScrollChoice("Window Name", scrolly, 25);
- break;
- case 3:
- s = DialogBox(diagbox, "sample");
- free(s);
- break;
- case 5:
- exit(0);
- }
- }
- * Ok.. this ends the commented out part
- */